Skip to content

feat(sdk)!: pure DPNS and DashPay document builders shared with embedders - #4632

Open
PastaPastaPasta wants to merge 2 commits into
v4.2-devfrom
feat/shared-dpns-dashpay-builders
Open

feat(sdk)!: pure DPNS and DashPay document builders shared with embedders#4632
PastaPastaPasta wants to merge 2 commits into
v4.2-devfrom
feat/shared-dpns-dashpay-builders

Conversation

@PastaPastaPasta

@PastaPastaPasta PastaPastaPasta commented Sep 8, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

Carries forward the pure-builder half of #4619, without that PR's request-driven FromProof<GetDocumentsRequest> verifier, which the SDK-first C++ embedding (next PR in this series) no longer needs: the SDK retains the rich query it built and verifies against it, so no wire request is reconstructed from bytes.

dash-sdk's register_dpns_name and create_contact_request assemble DPNS and DashPay documents inline. An embedder that signs with a wallet-held key (Dash Core's platform GUI) needs the same assembly as a pure function over caller-supplied entropy, salt and ciphertexts, and must not reimplement it in C++.

What was done?

Pure document builders, in dash-platform-queries:

  • dpns_usernames::{build_dpns_preorder_document, build_dpns_domain_document, salted_domain_hash} and dashpay::build_contact_request_document, the assembly halves of dash-sdk's register_dpns_name / create_contact_request as pure functions. dash-sdk's networked flows now call them.
  • They reuse what exists rather than re-deriving it: normalization is dpp's consensus convert_to_homograph_safe_chars (the crate's ASCII-only copy is replaced by a re-export); the preorder commitment uses dpp::util::hash::hash_double; property names come from the dpns-contract / dashpay-contract constants; the DashPay byte bounds are read from the contract schema's DocumentPropertyType sizes instead of being hard-coded to the same numbers.

This is a move, not a rewrite. The documents the builders produce are byte for byte what the inline SDK code produced. The normalization swap is the only substitution, and the two implementations agree on every label the contract's ASCII-only pattern admits — they differ only on non-ASCII input, which consensus rejects anyway. The re-export additionally makes the crate agree with the DPNS data trigger.

Deliberately not in this PR

Two behaviour changes were dropped to keep this reviewable as a pure extraction. Both are worth doing on their own:

  • No new label validation. An earlier revision rejected labels via is_valid_username before the preorder was paid for. That helper is stricter than the DPNS contract — it also refuses consecutive hyphens, which the contract's ^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$ pattern admits — so it would have refused names Platform accepts, on paths (wasm-sdk, platform-wallet) that previously had no local check at all. Failing early on a bad label is a real improvement, but it should check the contract's actual pattern, and it belongs in its own PR alongside a fix to is_valid_username's docstring, which currently claims the pattern forbids consecutive hyphens.
  • No entropy/document-id check in dpp. dash-sdk keeps its existing private ensure_entropy_matches_document_id. Hoisting it into DocumentCreateTransitionV0::from_document so every caller (SDK, wasm, FFI, embedders) inherits it is a good change — it cannot change any outcome, since it only refuses transitions Drive would reject after the nonce bump — but it adds an error path to a shared crate and is separable from this move.

packages/rs-dpp and put_document.rs are therefore byte-identical to v4.2-dev in this PR.

The autoAcceptProof bound is still checked in create_contact_request before the recipient lookup. The shared builder re-checks it against the schema, but that field is raw caller input and the lookup is a network round trip, so the early rejection is preserved. The two checks on the SDK's own encryption output are dropped as unreachable code — the pre-existing COMPACT_XPUB_LEN guard forces the encrypted xpub to 96 bytes, and fit_account_label bounds the encrypted label to 48-80 — and the builder covers both for embedders doing their own encryption.

How Has This Been Tested?

  • dash-platform-queries: 60 lib tests pass, including builder tests against the real DPNS/DashPay system contracts (preorder commitment matches the domain document's salt+label, id derivation, schema byte-bound enforcement).
  • dash-sdk --lib: 187 pass. cargo check clean for platform-wallet, rs-sdk-ffi, strategy-tests, rs-scripts. cargo fmt --check clean.
  • Byte-parity check: a scratch test reproduced the pre-PR inline assembly verbatim (including the old ASCII normalizer and the old sha256d helper) and asserted document equality against the new builders, across several DPNS labels — including alice--bob, -bad and ab, which the dropped gate used to reject — and a contact request with every optional field populated. All equal. Not committed; it exists only to prove the extraction.
  • Not done here: a live-network run of register_dpns_name / send_contact_request. The on-wire behaviour is byte-identical by construction and the unit tests pin the property maps.

Breaking Changes

API shape on unreleased v4.2-dev (not on crates.io): dash_sdk::platform::dashpay::ContactRequestResult now carries the assembled document plus entropy instead of id / owner_id / properties. No consumer outside rs-sdk uses it. No behavioural breaking changes.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • New Features

    • Added helpers for creating DashPay contact request documents with encrypted-field validation.
    • Added helpers for creating DPNS preorder and domain documents, including label normalization and salted hash generation.
    • Exposed document-building utilities through the DashPay and DPNS SDK modules.
  • Improvements

    • Contact request and DPNS registration workflows now share document construction and validation.
    • Improved handling of data contract validation errors.
  • Tests

    • Expanded automated coverage for contact requests and DPNS document creation.

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 4ad0b256-5ee5-493c-95b0-9993ddf64813

📥 Commits

Reviewing files that changed from the base of the PR and between cfb93ac and 796a86b.

📒 Files selected for processing (2)
  • .github/workflows/tests-rs-workspace.yml
  • packages/dash-platform-queries/src/dashpay.rs

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds transport-free DashPay contact request and DPNS document builders. The SDK now uses these builders for document creation, validation, identifier generation, and submission. The builders are publicly re-exported through the platform SDK modules.

Changes

Document builder foundation

Layer / File(s) Summary
DPNS document builders
packages/dash-platform-queries/src/dpns_usernames.rs, packages/dash-platform-queries/Cargo.toml, packages/rs-sdk/src/platform/dpns_usernames/mod.rs, .github/workflows/tests-rs-workspace.yml
The shared DPNS helpers build preorder and domain documents, normalize labels through dpp, compute salted domain hashes, and derive document IDs from entropy. The workflow now runs tests for dash-platform-queries.
DashPay contact request builder
packages/dash-platform-queries/src/dashpay.rs, packages/dash-platform-queries/src/error.rs, packages/dash-platform-queries/src/lib.rs, packages/rs-sdk/src/platform/dashpay/mod.rs
The shared DashPay helper validates encrypted fields against contract schema bounds and assembles contact request documents with entropy-derived IDs. The helper and parameter type are publicly re-exported.
DashPay SDK integration
packages/rs-sdk/src/platform/dashpay/contact_request.rs
Contact request creation returns the assembled document and entropy. Submission reuses the document directly.
DPNS SDK integration
packages/rs-sdk/src/platform/dpns_usernames/mod.rs
DPNS registration delegates document construction to the shared helpers and re-exports the new APIs.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DashPaySDK
  participant ContactRequestBuilder
  participant DashpayContract
  participant Platform
  DashPaySDK->>ContactRequestBuilder: Build contact request parameters
  ContactRequestBuilder->>DashpayContract: Resolve contactRequest schema
  ContactRequestBuilder-->>DashPaySDK: Return validated document and entropy
  DashPaySDK->>Platform: Submit the document with entropy
  Platform-->>DashPaySDK: Return submission result
Loading
sequenceDiagram
  participant DPNSSDK
  participant DPNSBuilders
  participant DPNSContract
  participant Platform
  DPNSSDK->>DPNSBuilders: Build preorder and domain documents
  DPNSBuilders->>DPNSContract: Resolve preorder and domain schemas
  DPNSBuilders-->>DPNSSDK: Return entropy-derived documents
  DPNSSDK->>Platform: Register the documents
  Platform-->>DPNSSDK: Return registration result
Loading

Merge Risk: ⚪ Minimal · up to 796a8

The change centralizes DPNS and DashPay document construction while preserving the existing SDK document behavior. No actionable correctness, security, or availability risk remains identified for merge.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 79.17% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 24 functions across 7 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: extracting pure DPNS and DashPay document builders for sharing with embedders. It is concise and specific.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 79.17% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 24 functions across 7 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/shared-dpns-dashpay-builders

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@PastaPastaPasta
PastaPastaPasta force-pushed the build/vendor-locked-single-source branch from 05927f9 to 1e8f252 Compare September 8, 2026 21:16
@PastaPastaPasta
PastaPastaPasta force-pushed the feat/shared-dpns-dashpay-builders branch from 0631c07 to 5279114 Compare September 8, 2026 21:16
Base automatically changed from build/vendor-locked-single-source to v4.2-dev September 8, 2026 21:57
@github-actions github-actions Bot added this to the v4.2.0 milestone Sep 8, 2026
@PastaPastaPasta
PastaPastaPasta force-pushed the feat/shared-dpns-dashpay-builders branch 2 times, most recently from 47b05e3 to cfb93ac Compare September 10, 2026 19:36
@PastaPastaPasta
PastaPastaPasta marked this pull request as ready for review September 10, 2026 19:37
@thepastaclaw

thepastaclaw commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

🕓 Queued for automated review — 4th in line, estimated start in ~35 min (commit 796a86b)
Estimated review time once started: ~25 min (two-phase automated review; median of recent runs).

  • Request priority review — tick this box and the review moves to the front of the queue.

@codecov

codecov Bot commented Sep 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.94872% with 22 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.41%. Comparing base (63cf57f) to head (796a86b).
⚠️ Report is 1 commits behind head on v4.2-dev.

Files with missing lines Patch % Lines
packages/dash-platform-queries/src/dashpay.rs 93.45% 11 Missing ⚠️
...ckages/dash-platform-queries/src/dpns_usernames.rs 92.85% 10 Missing ⚠️
packages/dash-platform-queries/src/error.rs 75.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           v4.2-dev    #4632      +/-   ##
============================================
- Coverage     87.86%   87.41%   -0.45%     
============================================
  Files          2766     2797      +31     
  Lines        360981   366966    +5985     
============================================
+ Hits         317162   320801    +3639     
- Misses        43819    46165    +2346     
Components Coverage Δ
dpp 87.73% <ø> (-1.38%) ⬇️
drive 86.52% <ø> (-0.07%) ⬇️
drive-abci 89.86% <ø> (+0.03%) ⬆️
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.92% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 49.78% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…ders

dash-platform-queries gains build_dpns_preorder_document /
build_dpns_domain_document / salted_domain_hash (dpns_usernames) and
build_contact_request_document (new dashpay module): the document-assembly
halves of dash-sdk's register_dpns_name and create_contact_request as pure
functions that take caller-supplied entropy, salt and ciphertexts and touch no
network or randomness. dash-sdk's networked flows now call them, so an embedder
that assembles its own transitions (the Dash Core platform GUI) and the SDK
share one implementation.

This is a move, not a rewrite: the documents these builders produce are byte
for byte what the inline SDK code produced. The builders lean on what the
codebase already has rather than re-deriving it: normalization is dpp's
consensus convert_to_homograph_safe_chars (the crate's ASCII-only copy, whose
non-ASCII behaviour differed from the data trigger's, is replaced by a
re-export; the two agree on every label the contract's ASCII-only pattern
admits); the preorder commitment uses dpp::util::hash::hash_double; property
names come from the dpns-contract / dashpay-contract constants; and the DashPay
byte-array bounds (96 / 48-80 / 38-102) are read from the contract schema
instead of being hard-coded to the same numbers.

Deliberately not changed here, to keep this reviewable as a pure extraction:

- No new label validation. An earlier draft rejected labels via
  is_valid_username before the preorder was paid for, but that helper is
  stricter than the DPNS contract (it also refuses consecutive hyphens, which
  the contract's pattern admits), so it would have refused names Platform
  accepts. Failing early on a bad label is worth doing on its own, against the
  contract's actual pattern; it is not this PR.
- No entropy/document-id consistency check in dpp. dash-sdk keeps its existing
  private ensure_entropy_matches_document_id. Hoisting that into
  DocumentCreateTransitionV0::from_document so every caller inherits it is a
  good change, but it adds an error path to a shared crate and is separable.

The autoAcceptProof bound is still checked in create_contact_request before the
recipient lookup: the shared builder re-checks it against the schema, but that
field is raw caller input and the lookup is a network round trip. The two
checks on the SDK's own encryption output are dropped as dead code — the
pre-existing COMPACT_XPUB_LEN guard forces the encrypted xpub to 96 bytes and
fit_account_label bounds the encrypted label to 48-80 — and the builder covers
both for embedders that do their own encryption.

API shape (unreleased v4.2-dev): ContactRequestResult now carries the assembled
document plus entropy instead of id/owner_id/properties; send_contact_request
no longer hand-rebuilds a DocumentV0.
@PastaPastaPasta
PastaPastaPasta force-pushed the feat/shared-dpns-dashpay-builders branch from cfb93ac to edb833b Compare September 10, 2026 20:18
The coverage phase of tests-rs-workspace.yml drives nextest from an explicit
package allowlist, and dash-platform-queries was never added to it when the
crate was split out of dash-sdk. The crate still reaches the report as a
dependency of dash-sdk, so llvm-cov instruments its lines — but its own test
binaries are never run, and every line it owns is recorded as a miss.

Two consequences: the crate's unit tests have not executed in CI since the
split, and any PR touching it is charged for uncovered lines that its tests
do in fact cover, which no amount of added testing can fix from the PR side.

Adding the package runs those tests and makes the reported coverage reflect
them. It only adds hits, since the lines were already in the denominator.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants